package com.koron.css2;


import com.koron.css2.newProjectCenter.function.bean.fromThirdParty.ThirdParty;
import com.koron.css2.serviceManage.bean.*;
import com.koron.css2.serviceManage.service.ServerService;
import com.koron.css2.serviceManage.utils.CommonUtils;
import com.koron.css2.serviceManage.utils.JsonUtils;
import com.koron.css2.serviceManage.utils.PageDetailLog;
import com.koron.css2.systemManage.bean.OperationTreeBean;
import com.koron.css2.systemManage.dto.UserAuthorityDto;
import com.koron.util.Constant;
import com.koron.util.DBSourceUtils;
import com.koron.util.InitParam;
import com.koron.util.Tools;
import nl.bitwalker.useragentutils.UserAgent;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.koron.ebs.mybatis.ADOConnection;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.swan.bean.MessageBean;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

/**
 * 所有前端ajax调用的公共入口
 * 
 * 本系统所有接口都采用插件式开发
 * 
 * 通过接口中的服务类型，从数据库获取服务类型对应的接口类，并执行
 * 
 * 统一进行权限判断，和服务日志调用等
 * 
 * @author 周新宇
 * @version 创建时间：2018年7月8日 上午8:34:06
 */
@Controller
public class InterFaceAction {
	
	@Autowired
	private ServerService serverService; // 服务管理类
	
	private static Logger logger = LogManager.getLogger(InterFaceAction.class);

	// 用于存储查询过的服务配置信息，这里不放redis而是放本地内存，访问更快
	private HashMap<String, TService> tServiceMap = new HashMap<>();

	// 用于存储所有接口的实例，在接口被调用一次之后，实例对象存储在这里，方便后续调用
	private HashMap<String, ServerInterface> serverMap = new HashMap<>();

	/**
	 * 根据不同的数据连接，通过业务实体对象，执行具体的服务信息
	 * 
	 * @param factory         数据库连接
	 * @param serverInterface 业务实体对象
	 * @param userInfo        用户信息
	 * @param requestBean     请求数据
	 * @return
	 */
	@TaskAnnotation("execInterface")
	public static MessageBean<?> execInterface(SessionFactory factory, ServerInterface serverInterface,
			UserInfoBean userInfo, RequestBean requestBean) throws Exception {
		MessageBean<?> ret = serverInterface.exec(factory, userInfo, requestBean); 
		if(ret.getCode() != Constant.MESSAGE_INT_SUCCESS) {
			factory.close(false);
		}
		return ret;
	}

	/**
	 * 所有业务系统操作数据的统一入口
	 * 
	 * @param requestBean 请求的对象数据
	 * @param request     请求Servlet对象
	 * @return ResponseBean 返回结果
	 */
	@ResponseBody
	@RequestMapping(value = ("/interface.api"), method = RequestMethod.POST)
	public ResponseBean service(@RequestBody RequestBean requestBean, HttpServletRequest request) {
		ResponseBean responseBean = new ResponseBean();
		if (requestBean == null || StringUtils.isBlank(requestBean.getBusicode()) || StringUtils.isBlank(requestBean.getSysType())) {
			responseBean.setCode(Constant.ILLEGAL_PARAMETER);
			responseBean.setDescription("请求的json格式不正确,或者参数为空");
			return responseBean;
		}
		UserInfoBean userInfo = Tools.getLoginBean(requestBean.getToken());
		if (userInfo == null) {
			responseBean.setCode(Constant.MESSAGE_INT_NOLOGIN);
			responseBean.setDescription("当前登录信息失效，请重新登录后再操作。");
			return responseBean;
		}
		UserAuthorityDto userAuthority = Tools.getUserAuthority(userInfo.getUserInfo().getAcount(), requestBean.getToken());
		if (userInfo.getCurService().equals(Constant.APP_CUSTOMER) && userAuthority == null) {
			responseBean.setCode(Constant.MESSAGE_INT_NOLOGIN);
			responseBean.setDescription("当前用户权限信息获取失败，请重新登录后再操作。");
			return responseBean;
		}
		// 获取IP地址
		userInfo.setIpAddr(CommonUtils.getIpAddress(request));
		// 获取服务信息
		TService tService = getInterfaceInfo(requestBean.getBusicode(), requestBean.getToken());
		if (tService == null) {
			responseBean.setCode(Constant.NO_DATA);
			responseBean.setDescription(requestBean.getBusicode() + "服务不存在");
			return responseBean;
		}
		// 判断服务是否停用
		if (tService.getStatus() == 0) {
			responseBean.setCode(Constant.SERVER_DISABLE);
			responseBean.setDescription(requestBean.getBusicode() + "该服务已停用");
			return responseBean;
		}
		// 执行服务
		try {
			String dbEnv = "_default";
			/*
			 * 001表示运维平台，002营收系统，003服务分析系统
			 */
		    if(userInfo.getCurService().equals(Constant.APP_CUSTOMER)) {
		    	if(tService.getDbMaster() == 1) {      // 主数据库
		    		dbEnv = DBSourceUtils.getDbEnv(userInfo.getCurWaterCode(), true);
		    	}else if(tService.getDbMaster() == 2){  // 从数据库
		    		dbEnv = DBSourceUtils.getDbEnv(userInfo.getCurWaterCode(), false);
		    		logger.info("当前的数据源为从库：{}", dbEnv);
		    	} else {
		    		dbEnv = DBSourceUtils.getDbEnv(userInfo.getCurWaterCode()); // 为空则为主库
		    	}
			}else if(userInfo.getCurService().equals(Constant.APP_ANALYSIS)) {
				
			}else if(userInfo.getCurService().equals(Constant.APP_DEVOPS)) {
				
			}
			if(dbEnv == null){
				throw new RuntimeException("水司编号为："+userInfo.getCurWaterCode()+"的数据源注册失败！");
			}
			// 从缓存中获取服务实例
			ServerInterface serverInterface = serverMap.get(requestBean.getBusicode());
			// 判断缓存中是否存在，不存在则实例化一个新的并放入缓存
			if (serverInterface == null) {
				serverInterface = (ServerInterface) Class.forName(tService.getClassName()).newInstance();
				serverMap.put(requestBean.getBusicode(), serverInterface);
			}
			//校验字段参数
			MessageBean<?> message = ADOConnection.runTask(dbEnv, InterFaceAction.class, "execInterface", serverInterface, userInfo, requestBean);
			responseBean.setCode(message.getCode());
			responseBean.setDescription(message.getDescription());
			responseBean.setData(message.getData());
		} catch (Exception e) {
			logger.error("操作失败", e);
			responseBean.setCode(Constant.MESSAGE_INT_FAIL);
			responseBean.setDescription(e.getMessage());
		}
		// 记录调用信息
		RecordLog(request, responseBean, requestBean, userInfo);
		return responseBean;
	}

	@ResponseBody
	@RequestMapping(value = ("register.api"), method = RequestMethod.POST)
	public void register(@RequestBody ThirdParty thirdParty, HttpServletRequest request) {
		String ipAddress = CommonUtils.getIpAddress(request);
		if (StringUtils.isBlank(ipAddress)) {
			logger.error("注册失败，ip地址为空");
			return;
		} else if (!CommonUtils.isIpAddress(ipAddress)) {
			logger.error("注册失败，ip地址格式不正确");
			return;
		} else if (!ApplicationConfig.getWhiteIp().equals(ipAddress)) {
			logger.error("注册失败，ip地址不在白名单中");
			return;
		}
		// 判断companyNo是否为空以及insertFlag是否为1
		if (StringUtils.isBlank(thirdParty.getCompanyNo())) {
			logger.error("注册失败，companyNo为空");
			return;
		}
		if (thirdParty.getConsult().getInsertFlag() != 1) {
			logger.error("注册失败，insertFlag不为1");
			return;
		}
		try {
			String dbEnv = DBSourceUtils.getDbEnv(thirdParty.getCompanyNo(), true);
			if (dbEnv == null) {
				logger.error("注册失败，水司编号：{}，数据源注册失败", thirdParty.getCompanyNo());
				return;
			}

		} catch (Exception e) {
			logger.error("注册失败", e);

		}
	}
	
	/**
	 * 获取单点登录地址
	 */
	@ResponseBody
	@RequestMapping(value = ("/getAppSSOUrl.api"), method = RequestMethod.GET)
	public MessageBean<?> getAppSSOUrl( HttpServletRequest request, HttpServletResponse response) {
		MessageBean<String> info = MessageBean.create(Constant.MESSAGE_INT_SUCCESS, "success", String.class);
		info.setCode(Constant.MESSAGE_INT_SUCCESS);
		info.setDescription("查询成功");
		// 粤海单点登录地址
		if (Objects.equals(Constant.UMA_SSO_PLAT, ApplicationConfig.getSsoPlatform())){
			info.setData(ApplicationConfig.getAppSSOUrl());
		}
		// 竹云 单点登录 地址
		if (Objects.equals(Constant.IAM_SSO_PLAT, ApplicationConfig.getSsoPlatform())){
			info.setData(ApplicationConfig.getIamLoginUrl());
		}
		return info;
	}

	@ResponseBody
	@RequestMapping(value = ("/file.api"), method = RequestMethod.GET)
	public void getFile(@RequestParam String path,HttpServletRequest request, HttpServletResponse response) {
		Path filePath = Paths.get(ApplicationConfig.getFileLocalPath(), path);
		File file = filePath.toFile();

		if (!file.exists()) {
			response.setStatus(HttpServletResponse.SC_NOT_FOUND);
			return;
		}

		// 设置正确的 Content-Type
		String mimeType = request.getServletContext().getMimeType(file.getAbsolutePath());
		if (mimeType == null) {
			mimeType = "application/octet-stream"; // 默认二进制流类型
		}
		response.setContentType(mimeType);

		try {
			String filename = file.getName();
			String userAgent = response.getHeader("User-Agent");
			String encodedFilename;

			// 根据浏览器类型选择编码方式
			if (userAgent != null && userAgent.contains("MSIE")) {
				// 针对 IE 浏览器
				encodedFilename = URLEncoder.encode(filename, "UTF-8").replace("+", " ");
			} else if (userAgent != null && userAgent.contains("Firefox")) {
				// 针对 Firefox 浏览器
				encodedFilename = "=?UTF-8?B?" + java.util.Base64.getEncoder().encodeToString(filename.getBytes("UTF-8")) + "?=";
			} else {
				// 针对其他浏览器（如 Chrome、Edge、Safari 等）
				encodedFilename = URLEncoder.encode(filename, "UTF-8");
			}

			// 设置 Content-Disposition 头
			response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFilename + "\"");

		} catch (Exception e) {
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		}

		// 返回文件数据
		try (FileInputStream fis = new FileInputStream(file);
			 OutputStream os = response.getOutputStream()) {

			byte[] buffer = new byte[1024];
			int bytesRead;
			while ((bytesRead = fis.read(buffer)) != -1) {
				os.write(buffer, 0, bytesRead);
			}
			os.flush();
		} catch (IOException e) {
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		}
	}

	/**
	 * 从本地内存读取服务配置，如果没有就从数据库读取
	 * 
	 * @param busicode
	 * @param token
	 * @return
	 */
	private TService getInterfaceInfo(String busicode, String token) {
		TService tService = tServiceMap.get(busicode);
		if (tService == null) {
			tService = ADOConnection.runTask("_default", serverService, "selectByServiceCode", TService.class,
					busicode);
			if(!InitParam.isDev) {
				tServiceMap.put(busicode, tService);
			}
		}
		return tService;
	}
	
	/**
	 * 检查用户权限
	 * @param userInfo
	 * @param tService
	 * @param url
	 * @return
	 */
	private boolean checkRight(UserInfoBean userInfo, TService tService, String url, RequestBean requestBean, UserAuthorityDto userAuthority) {
		List<OperationTreeBean> operations = userAuthority.getOperations();
		//List<String> urls = operations.stream().map(t -> t.getUrl()).collect(Collectors.toList());
		List<String> urls = new ArrayList();
		getOperationUrls(operations,urls);
		if(url!=null) {
			url=url.replace("#", "");
		}
		if(!urls.contains(url)) {
			return false; 
		}
		return true; 
	} 
	
	/**
	 * 迭代取菜单地址
	 */
	private static void getOperationUrls(List<OperationTreeBean> operations,List<String> urls) {
		if(operations!=null && operations.size()>0) {
			for(OperationTreeBean bean:operations) {
				if(bean.getUrl()!=null) {
					urls.add(bean.getUrl().replace("#", ""));
				}else {
					urls.add(bean.getUrl());
				}
				if(bean.getChildren()!=null && bean.getChildren().size()>0)
					getOperationUrls(bean.getChildren(),urls);
			}
		}
		return ;
	
	}

	/**
	 * 记录调用日志
	 * 
	 * @param request
	 * @param responseBean
	 * @param requestBean
	 * @param userInfo
	 */
	private void RecordLog(HttpServletRequest request, ResponseBean responseBean, RequestBean requestBean,
			UserInfoBean userInfo) {
		try {
			RecordBean recordBean = new RecordBean();
			String ua = request.getHeader("User-Agent");
			UserAgent userAgent = UserAgent.parseUserAgentString(ua);
			String browser = userAgent.getBrowser().getName();
			recordBean.setBrowserType(browser);
			recordBean.setWaterGroup(userInfo.getCurWaterCode());
			if (StringUtils.isBlank(userInfo.getCurWaterCode())) {
				recordBean.setWaterGroup("运维平台");
			}
			recordBean.setComments("调用" + requestBean.getBusicode());
			recordBean.setIpAddr(CommonUtils.getIpAddress(request));
			if (!StringUtils.isBlank(request.getHeader("url"))) {
				recordBean.setPageAddr(request.getHeader("url"));
			} else {
				recordBean.setPageAddr("abc(请求头header中未传递url信息)");
			}
			recordBean.setCaller(userInfo.getUserInfo().getAcount());
			recordBean.setCreateName(userInfo.getUserInfo().getName());
			recordBean.setCreateTime(CommonUtils.getCurrentTime());
			recordBean.setServiceCode(requestBean.getBusicode());
			recordBean.setRequest(JsonUtils.objectToJson(requestBean));
			recordBean.setResponse(JsonUtils.objectToJson(responseBean));

			PageDetailLog.put(recordBean);
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
	}
}
